package com.koron.css2;

import com.koron.common.stub.Port;
import com.koron.css2.common.dto.HeaderInfoDto;
import com.koron.css2.common.utils.ExcelUtils;
import com.koron.css2.common.utils.TxtUtils;
import com.koron.css2.serviceManage.bean.*;
import com.koron.css2.serviceManage.service.ServerService;
import com.koron.css2.serviceManage.utils.CommonUtils;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.css2.serviceManage.utils.PageDetailLog;
import com.koron.util.Constant;
import com.koron.util.DBSourceUtils;
import com.koron.util.InitParam;
import com.koron.util.Tools;
import nl.bitwalker.useragentutils.UserAgent;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.swan.bean.MessageBean;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;


/**
 * 文件导入公共入口类
 * @author 周利斌
 *
 */
@Controller
public class ImportExcelAction {
	
//	@Resource
//	private JedisPool jedisPool; // redis缓存池
	
	@Autowired
	private ServerService serverService; // 服务管理类

	private static Logger logger = LoggerFactory.getLogger(ImportExcelAction.class);

	// 用于存储查询过的服务配置信息，这里不放redis而是放本地内存，访问更快
	private HashMap<String, TService> tServiceMap = new HashMap<>();

	// 用于存储所有接口的实例，在接口被调用一次之后，实例对象存储在这里，方便后续调用
	private HashMap<String, ImportExcelInterface> serverMap = new HashMap<String, ImportExcelInterface>();

	/**
	 * 
	 * @param factory 数据源
	 * @param serverInterface 业务处理接口
	 * @param userInfo 当前用户信息
	 * @param result 读取导入的文件信息
	 * @return
	 * @throws Exception
	 */
	@TaskAnnotation("importExcel")
	public static MessageBean<?> importExcel(SessionFactory factory, ImportExcelInterface serverInterface, UserInfoBean userInfo, RequestBean req,List<Map<String, String>> result, MultipartFile file) throws Exception {
		MessageBean<?> ret =  serverInterface.importExel(factory, userInfo, req,result, file);
		if(ret.getCode() != Constant.MESSAGE_INT_SUCCESS) {
			factory.close(false);
		}
		return ret;
	}
	
	/**
	 * 获取导入的文件信息
	 * @param headerInfos  业务处理类传过来的表头信息
	 * @param data  导入的文件数据
	 * @param headers 导入的文件数据表头
	 * @return
	 * @throws IOException
	 */
	private List<Map<String, String>> getImportExcelData(List<HeaderInfoDto> headerInfos, List<String[]> data, String[] headers) throws IOException{
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		for(int i = 0; i < data.size(); i++) {
			String[] rowData = data.get(i);
			Map<String, String> map = new HashMap<String, String>();
			for(int j = 0; j < headers.length; j++) {
				for (int k = 0; k < headerInfos.size(); k++){
					if (Objects.equals(headerInfos.get(k).getName(), headers[j])){
						if ((j + 1) <= rowData.length){
							map.put(headerInfos.get(k).getCode(), rowData[j]);
						}else {
							map.put(headerInfos.get(k).getCode(), StringUtils.EMPTY);
						}
					}
				}
			}
			result.add(map);
		}
		return result;
	}
	
	private List<Map<String, String>> getImportExcelData(List<String[]> data) throws IOException{
		List<Map<String, String>> result = new ArrayList<Map<String,String>>();
		for(int i = 0; i < data.size(); i++) {
			String[] rowData = data.get(i);
			Map<String, String> map = new HashMap<String, String>();
			for(int j = 0; j < rowData.length; j++) {
				map.put((j+1)+"", rowData[j]);
			}
			result.add(map);
		}
		return result;
	}
	
	/**
	 * 检查表头是否符合规范
	 * @param headerInfos 业务处理类传过来的表头信息
	 * @param headers 导入的文件数据表头
	 * @return
	 */
	private boolean checkHeader(List<HeaderInfoDto> headerInfos, String[] headers) {
		for(int i = 0; i < headerInfos.size(); i++) {
			boolean check = false;
			HeaderInfoDto headerInfo = headerInfos.get(i);
			for(int j = 0; j < headers.length; j++) {
				if (StringUtils.isNotEmpty(headers[j])) {
					if (Objects.equals(headerInfo.getName().trim(), headers[j].trim())) {
						check = true;
					}
				}
			}
			if(headerInfo.isRequired() && !check) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 所有业务系统，导入功能的统一入口
	 * 目前支持：excel，txt，ret
	 * 
	 * @param json 请求的对象数据
	 * @param request     请求Servlet对象
	 * @return ResponseBean 返回结果
	 * @throws Exception 
	 */
	@ResponseBody
	@RequestMapping(value = "/importExcel.api", method = RequestMethod.POST)
	public ResponseBean service(@RequestParam(required = true, name = "file") MultipartFile file,
		     @RequestParam(required = true, name = "json") String json, HttpServletRequest request) throws Exception {
		// 1. 对参数进行判空
		ResponseBean responseBean = new ResponseBean();
		RequestBean requestBean = JsonUtils.jsonToPojo(json, RequestBean.class);
		if (requestBean == null || StringUtils.isBlank(requestBean.getBusicode())
				|| StringUtils.isBlank(requestBean.getSysType())) {
			responseBean.setCode(Constant.ILLEGAL_PARAMETER);
			responseBean.setDescription("请求的json格式不正确,或者参数为空");
			return responseBean;
		}
		// 2. 获取用户信息(包括用户信息，用户可选水司信息，用户当前水司信息)
		UserInfoBean userInfo = Tools.getLoginBean(requestBean.getToken());
		if (userInfo == null) {
			responseBean.setCode(Constant.MESSAGE_INT_NOLOGIN);
			responseBean.setDescription("当前登录信息失效，请重新登录后再操作。");
			return responseBean;
		}

		// 3. 获取服务信息
		TService tService = getInterfaceInfo(requestBean.getBusicode(), requestBean.getToken());
		if (tService == null) {
			responseBean.setCode(Constant.NO_DATA);
			responseBean.setDescription(requestBean.getBusicode() + "服务不存在");
			return responseBean;
		}
		// 4. 判断服务是否停用
		if (tService.getStatus() == 0) {
			responseBean.setCode(Constant.SERVER_DISABLE);
			responseBean.setDescription(requestBean.getBusicode() + "该服务已停用");
			return responseBean;
		}
		// 5. 检查用户是否有该服务的权限
		if (!checkRight(userInfo, tService, request.getHeader("url"), requestBean)) {
			responseBean.setCode(Constant.NO_AUTHORITY);
			responseBean.setDescription("您无当前操作的权限("+requestBean.getBusicode()+")，请联系管理员处理！");
			return responseBean;
		}
		// 6. 执行服务
		try {
			// 6.1 数据库连接别名
			String dbEnv = "_default";
			List<String[]> data = null;   
			String[] headers = null;
			/*
			 * 001表示运维平台，002营收系统，003服务分析系统
			 */
		    if(userInfo.getCurService().equals("002")) {
				dbEnv = DBSourceUtils.getDbEnv(userInfo.getCurWaterCode());
			}else if(userInfo.getCurService().equals("003")) {
				//TODO
			}
			if(dbEnv == null){
				throw new RuntimeException("水司编号为："+userInfo.getCurWaterCode()+"的数据源注册失败！");
			}
			// 从缓存中获取服务实例
			ImportExcelInterface serverInterface = serverMap.get(requestBean.getBusicode());
			// 判断缓存中是否存在，不存在则实例化一个新的并放入缓存
			if (serverInterface == null) {
				serverInterface = (ImportExcelInterface) Class.forName(tService.getClassName()).newInstance();
				serverMap.put(requestBean.getBusicode(), serverInterface);
			}
			//获取文件头信息
			List<HeaderInfoDto> headerInfos = serverInterface.getHeaderInfo(userInfo);
			String filename = file.getOriginalFilename();
			String fileType = FilenameUtils.getExtension(filename);
			if(StringUtils.isBlank(fileType)) {
				throw new RuntimeException("非法文件不能导入");
			}
			//通过导入的文件读取文件信息
			if(Objects.equals("xlsx", fileType) || Objects.equals("xls", fileType)) {
				headers = ExcelUtils.readExcelHeader(file.getBytes(), filename);
				data = ExcelUtils.readExcelData(file.getBytes(), filename, true);
			}else if(Objects.equals("txt", fileType)) {
				headers = TxtUtils.readTxtHeader(file.getBytes(), filename);
				data = TxtUtils.readTxtData(file.getBytes());
			}else if(Objects.equals("RET", fileType)) {
				headers = TxtUtils.readTxtHeader(file.getBytes(), filename);
				data = TxtUtils.readTxtData(file.getBytes());
			} else {
				throw new RuntimeException("不支持的文件类型");
			}
			//获取导入数据转化为 List<Map<String, String>>
			List<Map<String, String>> result = null;
			//是否检查文件头
			if(serverInterface.isCheckHeader()) {
				//检查文件头是否规范
				if(!checkHeader(headerInfos, headers)) {
					throw new RuntimeException("文件头不规范不能导入");
				}
				result = getImportExcelData(headerInfos, data, headers);
			} else {
				result = getImportExcelData(data);
			}
			
			//业务实现处理类 将数据写入数据库
			MessageBean<?> runTask = ADOConnection.runTask(dbEnv, ImportExcelAction.class, "importExcel", serverInterface, userInfo,requestBean, result, file);
			responseBean.setCode(runTask.getCode());
			responseBean.setDescription(runTask.getDescription());
			responseBean.setData(runTask.getData());
		} catch (Exception e) {
			logger.error("操作失败", e);
			responseBean.setCode(Constant.MESSAGE_INT_FAIL);
			responseBean.setDescription(e.getMessage());
		}
		// 记录调用信息
		RecordLog(request, responseBean, requestBean, userInfo);
		return responseBean;
	}

	/**
	 * 从本地内存读取服务配置，如果没有就从数据库读取
	 * 
	 * @param busicode
	 * @param resource
	 * @param redisAavailable
	 * @return
	 */
	private TService getInterfaceInfo(String busicode, String token) {
		TService tService = tServiceMap.get(busicode);
		if (tService == null) {
			tService = ADOConnection.runTask("_default", serverService, "selectByServiceCode", TService.class,
					busicode);
			if(!InitParam.isDev) {
				tServiceMap.put(busicode, tService);
			}
		}
		return tService;
	}
	
	/**
	 * 检查用户权限
	 * 
	 * @param userInfo
	 * @param tService
	 * @param url
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private boolean checkRight(UserInfoBean userInfo, TService tService, String url, RequestBean requestBean) {
		if (userInfo.getUserInfo().getAcount().equals("admin")) {
			return true;
		}
		List<TServiceDetail> detailList =  tService.gettServiceDetails();
		if(detailList==null||detailList.size()==0) {//接口没有权限控制
			return true;
		}
		if("krrjdev123".equals(requestBean.getToken())){
			return true;
		}
		for(TServiceDetail detail :detailList) {
			//只有子系统，没有模块的，且子系统与当前用户登陆一致
			if(userInfo.getCurService().equals(detail.getSystemCode())&& StringUtils.isBlank(detail.getModuleId())) {
				return true;
			}else if(userInfo.getCurService().equals(detail.getSystemCode())&& StringUtils.isNotBlank(detail.getModuleId())&&
					detail.getModuleId().substring(detail.getModuleId().indexOf("_")+1).equals(url)) {
				//模块不为空,且模块编号与url地址一致，要调用接口验证权限
				Port port = null;
				if("001".equals(userInfo.getCurService())) {
					port = new Port(ApplicationConfig.appMaintainAppid, ApplicationConfig.appMaintainSecret);
				}else if("002".equals(userInfo.getCurService())) {
					port = new Port(ApplicationConfig.appCustomerAppid, ApplicationConfig.appCustomerSecret);
				}else if("003".equals(userInfo.getCurService())) {
					port = new Port(ApplicationConfig.appAnalysisAppid, ApplicationConfig.appAnalysisSecret);
				}
				try {
					MessageBean<?> test =port.operateTest(detail.getModuleId(),userInfo.getUserInfo().getCode() ,"{}");
					if(test ==null || test.getCode() != Constant.MESSAGE_INT_SUCCESS) {
						return false;
					}else {
						Map<String,Boolean> m = (Map<String,Boolean>)test.getData();
						if(!m.get(detail.getModuleId())) { //返回没有操作权限
							return false;
						}else {
							return true;
						}
					}
				} catch (Exception e) {
					return false;
				}
			}
		}
		//TODO 重写上面权限认证方法
		return true; //false
	}

	/**
	 * 记录调用日志
	 * 
	 * @param request
	 * @param responseBean
	 * @param requestBean
	 * @param userInfo
	 */
	private void RecordLog(HttpServletRequest request, ResponseBean responseBean, RequestBean requestBean,
			UserInfoBean userInfo) {
		try {
			RecordBean recordBean = new RecordBean();
			String ua = request.getHeader("User-Agent");
			UserAgent userAgent = UserAgent.parseUserAgentString(ua);
			String browser = userAgent.getBrowser().getName();
			recordBean.setBrowserType(browser);
			recordBean.setWaterGroup(userInfo.getCurWaterCode());
			if (StringUtils.isBlank(userInfo.getCurWaterCode())) {
				recordBean.setWaterGroup("运维平台");
			}
			recordBean.setComments("调用" + requestBean.getBusicode());
			recordBean.setIpAddr(CommonUtils.getIpAddress(request));
			if (!StringUtils.isBlank(request.getHeader("url"))) {
				recordBean.setPageAddr(request.getHeader("url"));
			} else {
				recordBean.setPageAddr("abc(请求头header中未传递url信息)");
			}
			recordBean.setCaller(userInfo.getUserInfo().getAcount());
			recordBean.setCreateName(userInfo.getUserInfo().getName());
			recordBean.setCreateTime(CommonUtils.getCurrentTime());
			recordBean.setServiceCode(requestBean.getBusicode());
			recordBean.setRequest(JsonUtils.objectToJson(requestBean));
			recordBean.setResponse(JsonUtils.objectToJson(responseBean));

			PageDetailLog.put(recordBean);
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}

}
